package com.zx.task.manager.components;

import com.alibaba.fastjson.JSON;
import com.zx.core.wrapper.ObjectWrapper;
import com.zx.core.wrapper.ResponseWrapper;
import com.zx.feign.client.NotificationServiceClient;
import com.zx.feign.client.dto.GetNotificationTemplateResponseDTO;
import com.zx.feign.client.dto.SystemNotificationDTO;
import com.zx.task.manager.model.Tasks;
import lombok.Builder;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;

/**
 * 任务通知组件
 * 负责发送与任务相关的各种通知
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class NotificationComponent {

    // 定义模板字段要求
    private static final Map<String, Set<String>> TEMPLATE_FIELD_REQUIREMENTS = new ConcurrentHashMap<>();

    static {
        // TASK_ASSIGNED 模板必需字段
        Set<String> taskAssignedFields = new HashSet<>();
        taskAssignedFields.add("executorName");
        taskAssignedFields.add("taskTitle");
        taskAssignedFields.add("taskDescription");
        TEMPLATE_FIELD_REQUIREMENTS.put("TASK_ASSIGNED", taskAssignedFields);

        // TASK_ACCEPTED 模板必需字段
        Set<String> taskAcceptedFields = new HashSet<>();
        taskAcceptedFields.add("taskTitle");
        taskAcceptedFields.add("executorName");
        taskAcceptedFields.add("estimatedTime");
        TEMPLATE_FIELD_REQUIREMENTS.put("TASK_ACCEPTED", taskAcceptedFields);

        // TASK_PROGRESS_UPDATE 模板必需字段
        Set<String> taskProgressUpdateFields = new HashSet<>();
        taskProgressUpdateFields.add("taskTitle");
        taskProgressUpdateFields.add("progress");
        taskProgressUpdateFields.add("updateRemark");
        TEMPLATE_FIELD_REQUIREMENTS.put("TASK_PROGRESS_UPDATE", taskProgressUpdateFields);

        // TASK_COMPLETED 模板必需字段
        Set<String> taskCompletedFields = new HashSet<>();
        taskCompletedFields.add("taskTitle");
        taskCompletedFields.add("executorName");
        taskCompletedFields.add("completionTime");
        taskCompletedFields.add("completionRemark");
        TEMPLATE_FIELD_REQUIREMENTS.put("TASK_COMPLETED", taskCompletedFields);

        // TASK_CANCELLED 模板必需字段
        Set<String> taskCancelledFields = new HashSet<>();
        taskCancelledFields.add("taskTitle");
        taskCancelledFields.add("cancelReason");
        taskCancelledFields.add("cancelTime");
        TEMPLATE_FIELD_REQUIREMENTS.put("TASK_CANCELLED", taskCancelledFields);

        // TASK_CLOSED 模板必需字段
        Set<String> taskClosedFields = new HashSet<>();
        taskClosedFields.add("taskTitle");
        taskClosedFields.add("closeReason");
        taskClosedFields.add("closeTime");
        TEMPLATE_FIELD_REQUIREMENTS.put("TASK_CLOSED", taskClosedFields);

        // TASK_OVERDUE_REMINDER 模板必需字段
        Set<String> taskOverdueReminderFields = new HashSet<>();
        taskOverdueReminderFields.add("taskTitle");
        TEMPLATE_FIELD_REQUIREMENTS.put("TASK_OVERDUE_REMINDER", taskOverdueReminderFields);

        // TASK_URGENT_NOTICE 模板必需字段
        Set<String> taskUrgentNoticeFields = new HashSet<>();
        taskUrgentNoticeFields.add("taskTitle");
        taskUrgentNoticeFields.add("priority");
        TEMPLATE_FIELD_REQUIREMENTS.put("TASK_URGENT_NOTICE", taskUrgentNoticeFields);
    }

    private final NotificationServiceClient notificationServiceClient;
    private final JsonTemplateProcessor jsonTemplateProcessor;

    /**
     * 发送任务分配通知
     *
     * @param task 任务信息
     */
    public void sendTaskAssignedNotification(Tasks task) {
        executeNotification(() -> {
            NotificationRequest request = NotificationRequest.builder()
                    .userId(task.getAssigneeId())
                    .templateCode("TASK_ASSIGNED")
                    .title("您有新的任务待签收")
                    .bizType("TASK")
                    .bizId(task.getId())
                    .bizUrl("/tasks/" + task.getId())
                    .build();

            Map<String, Object> templateData = new HashMap<>();
            templateData.put("executorName", task.getAssigneeName());
            templateData.put("taskTitle", task.getTitle());
            templateData.put("taskDescription", task.getDescription());

            return new NotificationContext(request, templateData);
        }, "任务分配通知", task.getId());
    }

    /**
     * 发送任务签收通知
     *
     * @param task         任务信息
     * @param acceptorName 签收人姓名
     */
    public void sendTaskAcceptedNotification(Tasks task, String acceptorName) {
        executeNotification(() -> {
            NotificationRequest request = NotificationRequest.builder()
                    .userId(task.getCreatorId())
                    .templateCode("TASK_ACCEPTED")
                    .title("任务已被签收")
                    .bizType("TASK")
                    .bizId(task.getId())
                    .bizUrl("/tasks/" + task.getId())
                    .build();

            Map<String, Object> templateData = new HashMap<>();
            templateData.put("taskTitle", task.getTitle());
            templateData.put("executorName", acceptorName);
            // TASK_ACCEPTED模板中使用的是estimatedTime而不是plannedStartTime和plannedEndTime
            templateData.put("estimatedTime", task.getPlannedEndTime());

            return new NotificationContext(request, templateData);
        }, "任务签收通知", task.getId());
    }

    /**
     * 发送任务进度更新通知
     *
     * @param task            任务信息
     * @param progressPercent 进度百分比
     * @param remark          备注
     */
    public void sendTaskProgressUpdateNotification(Tasks task, Integer progressPercent, String remark) {
        executeNotification(() -> {
            NotificationRequest request = NotificationRequest.builder()
                    .userId(task.getCreatorId())
                    .templateCode("TASK_PROGRESS_UPDATE")
                    .title("任务进度已更新")
                    .bizType("TASK")
                    .bizId(task.getId())
                    .bizUrl("/tasks/" + task.getId())
                    .build();

            Map<String, Object> templateData = new HashMap<>();
            templateData.put("taskTitle", task.getTitle());
            templateData.put("progress", progressPercent);
            templateData.put("updateRemark", remark);

            return new NotificationContext(request, templateData);
        }, "任务进度更新通知", task.getId());
    }

    /**
     * 发送任务完成通知
     *
     * @param task             任务信息
     * @param executorName     执行人姓名
     * @param completionTime   完成时间
     * @param completionRemark 完成备注
     */
    public void sendTaskCompletedNotification(Tasks task, String executorName, LocalDateTime completionTime, String completionRemark) {
        executeNotification(() -> {
            NotificationRequest request = NotificationRequest.builder()
                    .userId(task.getCreatorId())
                    .templateCode("TASK_COMPLETED")
                    .title("任务已完成")
                    .bizType("TASK")
                    .bizId(task.getId())
                    .bizUrl("/tasks/" + task.getId())
                    .build();

            Map<String, Object> templateData = new HashMap<>();
            templateData.put("taskTitle", task.getTitle());
            templateData.put("executorName", executorName);
            // TASK_COMPLETED模板中使用的是completionTime而不是LocalDateTime类型的completionTime
            templateData.put("completionTime", completionTime.toString());
            templateData.put("completionRemark", completionRemark);

            return new NotificationContext(request, templateData);
        }, "任务完成通知", task.getId());
    }

    /**
     * 发送任务取消通知
     *
     * @param task         任务信息
     * @param cancelReason 取消原因
     * @param cancelTime   取消时间
     */
    public void sendTaskCancelledNotification(Tasks task, String cancelReason, Date cancelTime) {
        executeNotification(() -> {
            NotificationRequest request = NotificationRequest.builder()
                    .userId(task.getAssigneeId())
                    .templateCode("TASK_CANCELLED")
                    .title("任务已取消")
                    .bizType("TASK")
                    .bizId(task.getId())
                    .bizUrl("/tasks/" + task.getId())
                    .build();

            Map<String, Object> templateData = new HashMap<>();
            templateData.put("taskTitle", task.getTitle());
            templateData.put("cancelReason", cancelReason);
            templateData.put("cancelTime", cancelTime);

            return new NotificationContext(request, templateData);
        }, "任务取消通知", task.getId());
    }

    /**
     * 发送任务关闭通知
     *
     * @param task        任务信息
     * @param closeReason 关闭原因
     * @param closeTime   关闭时间
     */
    public void sendTaskClosedNotification(Tasks task, String closeReason, Date closeTime) {
        executeNotification(() -> {
            NotificationRequest request = NotificationRequest.builder()
                    .userId(task.getAssigneeId())
                    .templateCode("TASK_CLOSED")
                    .title("任务已关闭")
                    .bizType("TASK")
                    .bizId(task.getId())
                    .bizUrl("/tasks/" + task.getId())
                    .build();

            Map<String, Object> templateData = new HashMap<>();
            templateData.put("taskTitle", task.getTitle());
            templateData.put("closeReason", closeReason);
            templateData.put("closeTime", closeTime);

            return new NotificationContext(request, templateData);
        }, "任务关闭通知", task.getId());
    }

    /**
     * 发送任务逾期提醒
     *
     * @param task 任务信息
     */
    public void sendTaskOverdueReminder(Tasks task) {
        executeNotification(() -> {
            NotificationRequest request = NotificationRequest.builder()
                    .userId(task.getAssigneeId())
                    .templateCode("TASK_OVERDUE_REMINDER")
                    .title("任务逾期提醒")
                    .bizType("TASK")
                    .bizId(task.getId())
                    .bizUrl("/tasks/" + task.getId())
                    .build();

            Map<String, Object> templateData = new HashMap<>();
            templateData.put("taskTitle", task.getTitle());

            return new NotificationContext(request, templateData);
        }, "任务逾期提醒", task.getId());
    }

    /**
     * 发送紧急任务通知
     *
     * @param task     任务信息
     * @param priority 优先级
     */
    public void sendTaskUrgentNotice(Tasks task, String priority) {
        executeNotification(() -> {
            NotificationRequest request = NotificationRequest.builder()
                    .userId(task.getAssigneeId())
                    .templateCode("TASK_URGENT_NOTICE")
                    .title("紧急任务通知")
                    .bizType("TASK")
                    .bizId(task.getId())
                    .bizUrl("/tasks/" + task.getId())
                    .build();

            Map<String, Object> templateData = new HashMap<>();
            templateData.put("taskTitle", task.getTitle());
            templateData.put("priority", priority);

            return new NotificationContext(request, templateData);
        }, "紧急任务通知", task.getId());
    }

    /**
     * 发送任务发布通知
     *
     * @param task 任务信息
     */
    public void sendTaskPublishedNotification(Tasks task) {
        executeNotification(() -> {
            NotificationRequest request = NotificationRequest.builder()
                    .userId(task.getAssigneeId())
                    .templateCode("TASK_ASSIGNED")
                    .title("您有新的任务待签收")
                    .bizType("TASK")
                    .bizId(task.getId())
                    .bizUrl("/tasks/" + task.getId())
                    .build();

            Map<String, Object> templateData = new HashMap<>();
            templateData.put("executorName", task.getAssigneeName());
            templateData.put("taskTitle", task.getTitle());
            templateData.put("taskDescription", task.getDescription());

            return new NotificationContext(request, templateData);
        }, "任务发布通知", task.getId());
    }

    /**
     * 通用发送通知方法
     *
     * @param userId       用户ID
     * @param templateCode 模板编码
     * @param title        通知标题
     * @param content      通知内容
     * @param bizType      业务类型
     * @param bizId        业务ID
     */
    public void sendGeneralNotification(String userId, String templateCode, String title, String content, String bizType, String bizId) {
        executeNotification(() -> {
            NotificationRequest request = NotificationRequest.builder()
                    .userId(userId)
                    .templateCode(templateCode)
                    .title(title)
                    .bizType(bizType)
                    .bizId(bizId)
                    .bizUrl("/" + bizType.toLowerCase() + "s/" + bizId)
                    .build();

            Map<String, Object> templateData = new HashMap<>();
            templateData.put("content", content);

            return new NotificationContext(request, templateData);
        }, "通用通知", bizId);
    }

    /**
     * 通用发送通知方法（完整参数版本）
     *
     * @param userId         用户ID
     * @param templateCode   模板编码
     * @param title          通知标题
     * @param content        通知内容
     * @param bizType        业务类型
     * @param bizId          业务ID
     * @param bizUrl         业务链接
     * @param targetChannels 目标渠道
     * @param expireTime     过期时间
     */
    public void sendNotification(String userId, String templateCode, String title, String content,
                                 String bizType, String bizId, String bizUrl, String targetChannels, LocalDateTime expireTime) {
        NotificationRequest request = NotificationRequest.builder()
                .userId(userId)
                .templateCode(templateCode)
                .title(title)
                .bizType(bizType)
                .bizId(bizId)
                .bizUrl(bizUrl)
                .build();

        try {
            // 构造通知参数
            SystemNotificationDTO notificationDTO = new SystemNotificationDTO();
            notificationDTO.setUserId(userId);
            notificationDTO.setTemplateCode(templateCode);
            notificationDTO.setTitle(title);
            notificationDTO.setContent(content);
            notificationDTO.setBizType(bizType);
            notificationDTO.setBizId(bizId);
            notificationDTO.setBizUrl(bizUrl);
            notificationDTO.setTargetChannels(targetChannels);
            notificationDTO.setCreateTime(LocalDateTime.now());
            notificationDTO.setExpireTime(expireTime);

            // 添加业务数据
            Map<String, Object> templateData = new HashMap<>();
            templateData.put("content", content);
            templateData.put("sendTime", new Date());
            String bizDataJson = JSON.toJSONString(templateData);
            notificationDTO.setBizData(bizDataJson);

            // 将DTO转换为JSON字符串
            String paramJsonStr = JSON.toJSONString(notificationDTO);

            // 调用通知服务发送通知
            ResponseWrapper response = notificationServiceClient.sendNotification(paramJsonStr);
            handleNotificationResult(response, request, "发送通知");
        } catch (Exception e) {
            logNotificationError(request, "发送通知", e);
        }
    }

    /**
     * 执行通知发送的统一方法
     *
     * @param contextSupplier 通知上下文提供者
     * @param operationName   操作名称（用于日志）
     * @param bizId           业务ID（用于日志）
     */
    private void executeNotification(Supplier<NotificationContext> contextSupplier, String operationName, String bizId) {
        try {
            NotificationContext context = contextSupplier.get();
            sendNotification(context.request(), context.templateData());
        } catch (Exception e) {
            log.error("发送{}失败: taskId={}", operationName, bizId, e);
        }
    }

    /**
     * 发送通知的核心方法
     *
     * @param request      通知请求参数
     * @param templateData 模板数据
     */
    private void sendNotification(NotificationRequest request, Map<String, Object> templateData) {
        try {
            // 验证模板必需字段
            if (!validateTemplateFields(request.templateCode(), templateData)) {
                log.error("模板字段验证失败: templateCode={}, missingFields={}",
                        request.templateCode(), getMissingFields(request.templateCode(), templateData));
                return;
            }

            // 从通知服务获取模板信息
            ObjectWrapper<GetNotificationTemplateResponseDTO> templateResponse = notificationServiceClient.getTemplateByCode(request.templateCode());
            GetNotificationTemplateResponseDTO template = null;
            if (!templateResponse.verifyFail()) {
                template = templateResponse.getData();
            }

            // 构造通知参数
            SystemNotificationDTO notificationDTO = new SystemNotificationDTO();
            notificationDTO.setUserId(request.userId());
            notificationDTO.setTemplateCode(request.templateCode());
            notificationDTO.setTitle(request.title());

            // 使用模板内容并结合数据生成最终内容
            String content = "默认内容";
            if (template != null) {
                // 将templateData转换为JSON字符串，然后使用JsonTemplateProcessor处理模板
                String templateDataJson = JSON.toJSONString(templateData);
                content = jsonTemplateProcessor.processTemplateWithJsonData(template.templateContent(), templateDataJson);
            }
            notificationDTO.setContent(content);

            notificationDTO.setBizType(request.bizType());
            notificationDTO.setBizId(request.bizId());
            notificationDTO.setBizUrl(request.bizUrl());

            // 添加业务数据
            String bizDataJson = JSON.toJSONString(templateData);
            notificationDTO.setBizData(bizDataJson);

            // 从模板中获取支持的渠道，如果获取不到则使用默认渠道
            String targetChannels = "INBOX";
            if (template != null && template.supportedChannels() != null) {
                targetChannels = template.supportedChannels();
            }
            notificationDTO.setTargetChannels(targetChannels);

            // 设置创建时间和过期时间
            LocalDateTime now = LocalDateTime.now();
            notificationDTO.setCreateTime(now);
            // 默认7天后过期
            notificationDTO.setExpireTime(now.plusDays(7));

            // 将DTO转换为JSON字符串
            String paramJsonStr = JSON.toJSONString(notificationDTO);

            // 调用通知服务发送通知
            ResponseWrapper response = notificationServiceClient.sendNotification(paramJsonStr);
            handleNotificationResult(response, request, "发送通知");
        } catch (Exception e) {
            logNotificationError(request, "发送通知", e);
        }
    }

    /**
     * 验证模板必需字段
     *
     * @param templateCode 模板编码
     * @param templateData 模板数据
     * @return 是否验证通过
     */
    private boolean validateTemplateFields(String templateCode, Map<String, Object> templateData) {
        Set<String> requiredFields = TEMPLATE_FIELD_REQUIREMENTS.get(templateCode);
        if (requiredFields == null) {
            // 如果没有定义模板要求，则默认验证通过
            return true;
        }

        // 检查所有必需字段是否存在且不为null
        for (String field : requiredFields) {
            if (!templateData.containsKey(field) || templateData.get(field) == null) {
                return false;
            }
        }

        return true;
    }

    /**
     * 获取缺失的字段列表
     *
     * @param templateCode 模板编码
     * @param templateData 模板数据
     * @return 缺失的字段列表
     */
    private Set<String> getMissingFields(String templateCode, Map<String, Object> templateData) {
        Set<String> missingFields = new HashSet<>();
        Set<String> requiredFields = TEMPLATE_FIELD_REQUIREMENTS.get(templateCode);

        if (requiredFields != null) {
            for (String field : requiredFields) {
                if (!templateData.containsKey(field) || templateData.get(field) == null) {
                    missingFields.add(field);
                }
            }
        }

        return missingFields;
    }

    /**
     * 处理通知发送结果
     *
     * @param response 响应结果
     * @param request  通知请求
     * @param action   操作名称
     */
    private void handleNotificationResult(ResponseWrapper response, NotificationRequest request, String action) {
        if (response.verifyFail()) {
            log.error("{}失败: userId={}, templateCode={}, title={}, errorMsg={}",
                    action, request.userId(), request.templateCode(), request.title(), response.getMsg());
        } else {
            log.info("成功{}给用户: {}, 模板: {}, 标题: {}",
                    action, request.userId(), request.templateCode(), request.title());
        }
    }

    /**
     * 记录通知错误日志
     *
     * @param request 通知请求
     * @param action  操作名称
     * @param e       异常
     */
    private void logNotificationError(NotificationRequest request, String action, Exception e) {
        log.error("{}异常: userId={}, templateCode={}, title={}",
                action, request.userId(), request.templateCode(), request.title(), e);
    }


    /**
     * 通知上下文
     */
    private record NotificationContext(NotificationRequest request, Map<String, Object> templateData) {
    }

    /**
     * 通知请求参数构建器
     */
    @Builder
    private record NotificationRequest(String userId, String templateCode, String title, String bizType, String bizId,
                                       String bizUrl) {
    }
}